package com.ljx.prototypeMode;

import lombok.Data;

/**
 * 原型模式
 *
 * 应用场景：
 * 当代码不应该依赖于需要复制的对象的具体类时，请使用原型模式
 *
 * 优点：
 * 1.可以不耦合具体类的情况下克隆对象
 * 2.避免重复的初始化代码
 * 3.更方便的构建复杂对象
 *
 * 经典应用：
 * Spring中，原型模式应用的非常广泛，例如 scope=‘prototype’、JSON.parseObject() 等都是原型模式的具体应用
 *
 * @作者 LJX
 * @日期 2022/12/20 14:57
 */
public class PrototypeModeTest {

    public static void main(String[] args) throws CloneNotSupportedException {
        GoodsInfo gi = new GoodsInfo("啦啦啦");
        Goods goods = new Goods("111", "222", "333", "444", "555", gi);
        Goods clone = goods.clone();
        GoodsInfo goodsInfo = goods.getGoodsInfo();
        goodsInfo.setGoodsName("靠靠靠");
        goods.setGoodsInfo(goodsInfo);
        System.out.println(goods);
        System.out.println(clone);
    }

}

@Data
class Goods implements Cloneable{
    private String attr1;
    private String attr2;
    private String attr3;
    private String attr4;
    private String attr5;
    private GoodsInfo goodsInfo;

    public Goods(String attr1, String attr2, String attr3, String attr4, String attr5, GoodsInfo goodsInfo) {
        this.attr1 = attr1;
        this.attr2 = attr2;
        this.attr3 = attr3;
        this.attr4 = attr4;
        this.attr5 = attr5;
        this.goodsInfo = goodsInfo;
    }

    @Override
    public String toString() {
        return super.hashCode() + "*****goodsInfoHC：" + goodsInfo.hashCode() + "*****Goods{" +
                "attr1='" + attr1 + '\'' +
                ", attr2='" + attr2 + '\'' +
                ", attr3='" + attr3 + '\'' +
                ", attr4='" + attr4 + '\'' +
                ", attr5='" + attr5 + '\'' +
                ", goodsInfo=" + goodsInfo +
                '}';
    }

    @Override
    protected Goods clone() throws CloneNotSupportedException {
        //引用变量子属性深拷贝
        //可以使用Java序列化实现深拷贝 但是效率不理想
        Goods clone = (Goods) super.clone();
        clone.setGoodsInfo(clone.getGoodsInfo().clone());
        return clone;
    }
}

@Data
class GoodsInfo implements Cloneable{
    private String goodsName;

    public GoodsInfo(String goodsName) {
        this.goodsName = goodsName;
    }

    @Override
    protected GoodsInfo clone() throws CloneNotSupportedException {
        return ((GoodsInfo) super.clone());
    }
}
